/*************************************************************************
                           Triangle  -  description
                             -------------------
    début                : 21 févr. 2012
    copyright            : (C) 2012 par francois
*************************************************************************/

//---------- Réalisation de la classe <Triangle> (fichier Triangle.cpp) -------

//---------------------------------------------------------------- INCLUDE

//-------------------------------------------------------- Include système
using namespace std;
#include <iostream>
#include <assert.h>
#include <math.h>

//------------------------------------------------------ Include personnel
#include "Triangle.h"
#include "Point2D.h"
#include "Vector2D.h"

namespace livgeo {

//------------------------------------------------------------- Constantes

//----------------------------------------------------------------- PUBLIC

//----------------------------------------------------- Méthodes publiques

void Triangle::createBoundingBox(Point2D& botLeft, Point2D& topRight)
{
	// X minimal
	float compP1P2 = (p1.getX() < p2.getX() ? p1.getX() : p2.getX());
	botLeft.setX( (p3.getX() < compP1P2) ? p3.getX() : compP1P2 );

	// Y Minimal
	compP1P2 = (p1.getY() < p2.getY() ? p1.getY() : p2.getY());
	botLeft.setY( (p3.getY() < compP1P2) ? p3.getY() : compP1P2 );

	// X Maximal
	compP1P2 = (p1.getX() > p2.getX() ? p1.getX() : p2.getX());
	topRight.setX( (p3.getX() > compP1P2) ? p3.getX() : compP1P2 );

	// Y Maximal
	compP1P2 = (p1.getY() > p2.getY() ? p1.getY() : p2.getY());
	topRight.setY( (p3.getY() > compP1P2) ? p3.getY() : compP1P2 );
}

bool Triangle::contains(const Point2D& p)
{
	static const Vector2D v0 = p3 - p1;
	static const Vector2D v1 = p2 - p1;
	Vector2D v2 = p - p1;

	static const float dot00 = Vector2D::dot(v0, v0);
	static const float dot01 = Vector2D::dot(v0, v1);
	float dot02 = Vector2D::dot(v0, v2);
	static const float dot11 = Vector2D::dot(v1, v1);
	float dot12 = Vector2D::dot(v1, v2);

	static const float invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
	float u = (dot11 * dot02 - dot01 * dot12) * invDenom;
	float v = (dot00 * dot12 - dot01 * dot02) * invDenom;

	return (u >= 0) && (v >= 0) && (u + v < 1);
	return true;
}

bool Triangle::intersectWith(const Vector2D& dir, const Point2D& p1, const Point2D& p2, Point2D& res)
{
	// TODO trouver un algo d'intersection ligne/triangle

	Point2D res1, res2, res3;

	if (!LineIntersect(this->p1, this->p2, p1, p2, res1)) return false;
	if (!LineIntersect(this->p2, this->p3, p1, p2, res2)) return false;
	if (!LineIntersect(this->p3, this->p1, p1, p2, res3)) return false;

	if (Vector2D::dot(res1 - p1,dir) > 0)
	{
		res.setX(res1.getX());
		res.setY(res1.getY());
	}
	else if (Vector2D::dot(res2 - p1,dir) > 0)
	{
		res.setX(res2.getX());
		res.setY(res2.getY());
	}
	else
	{
		res.setX(res3.getX());
		res.setY(res3.getY());
	}

	return true;
}

bool Triangle::LineIntersect(const Point2D& p1, const Point2D& p2,
    		const Point2D& p3, const Point2D& p4, Point2D& outP)
{
	float det = (p1.getX() - p2.getX())*(p3.getY() - p4.getY()) -
			(p1.getY() - p2.getY())*(p3.getX() - p4.getX());

	if (det == 0)
		return false;

	float det1 = p1.getX()*p2.getY() - p1.getY()*p2.getX();
	float det2 = p3.getX()*p4.getY() - p3.getY()*p4.getX();

	outP.setX( (det1*(p3.getX() - p4.getX()) - det2*(p1.getX() - p2.getX()) ) / det );
	outP.setY( (det1*(p3.getY() - p4.getY()) - det2*(p1.getY() - p2.getY()) ) / det );

	return true;

}

//------------------------------------------------- Surcharge d'opérateurs

//-------------------------------------------- Constructeurs - destructeur

Triangle::Triangle ( const Point2D& a, const Point2D& b, const Point2D& c) :
		p1(a), p2(b), p3(c)
{

} //----- Fin de Triangle

Triangle::Triangle(const Point2D& center, float angleDirection, float angleFov,
		float radius) :
		p2(center)
{
	assert(angleFov > 0);

	float angleP1 = angleDirection + angleFov / 2;
	float angleP3 = angleDirection - angleFov / 2;

	p1.setX(center.getX() - sin(angleP1) * radius);
	p1.setY(center.getY() + cos(angleP1) * radius);

	p3.setX(center.getX() - sin(angleP3) * radius);
	p3.setY(center.getY() + cos(angleP3) * radius);
}

Triangle::~Triangle ( )

{
} //----- Fin de ~Triangle


//------------------------------------------------------------------ PRIVE

//----------------------------------------------------- Méthodes protégées

}; // ------ fin de livgeo
